namespace SimpleWebServices.Net
{
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Xml;
    using System.Xml.XPath;
    using SimpleWebServices.Xml;

    public sealed class XmlXpathEvaluateTest<T> : HtmlXpathTest, ITestHttpExpectation
    {
        public XmlXpathEvaluateTest(T expected, string xpath)
            : this(expected, xpath, null)
        {
        }

        public XmlXpathEvaluateTest(T expected, string xpath, IEnumerable<XmlNamespace> namespaces)
            : this(expected, XPathExpression.Compile(xpath), namespaces)
        {
        }

        public XmlXpathEvaluateTest(T expected, XPathExpression xpath, IEnumerable<XmlNamespace> namespaces)
            : base(xpath)
        {
            this.Expected = expected;
            this.Namespaces = namespaces;
        }

        public T Expected
        {
            get;
            set;
        }

        public IEnumerable<XmlNamespace> Namespaces
        {
            get;
            set;
        }

        public bool Check(Response response)
        {
            return this.Check(response as XmlResponse);
        }

        private bool Check(XmlResponse response)
        {
            if (null == response)
            {
                throw new ArgumentNullException("response");
            }

            XPathNavigator navigator = response.Xml.CreateNavigator();

            if (null != this.Namespaces)
            {
                XmlNamespaceManager namespaces = new XmlNamespaceManager(navigator.NameTable);
                foreach (XmlNamespace item in this.Namespaces)
                {
                    namespaces.AddNamespace(item.Prefix, item.Uri);
                }

                this.Expression.SetContext(namespaces);
            }

            T actual = (T)navigator.Evaluate(this.Expression);
            if (!this.Expected.Equals(actual))
            {
                string message = string.Format(CultureInfo.InvariantCulture, "XML XPath : {0}\r\n expected: {1}\r\n actual: {2}", this.Expression.Expression, this.Expected.ToString(), actual.ToString());
                throw new HttpTestException(response, message);
            }

            return true;
        }
    }
}